﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using GTA;
using GTAHookAdv.Screen;

[assembly:InternalsVisibleTo("GTA4HookAdv_OverlayTests")]
namespace GTAHookAdv.Overlay
{

    /// <summary>
    /// Values to Define how Borders should be drawn
    /// </summary>
    public enum BorderStyleValues
    {
        /// <summary>
        /// No Borders
        /// </summary>
        None,
        /// <summary>
        /// Simply draw edges only
        /// </summary>
        /// <seealso cref="IControlOverlay.BackColor"/>
        Simple,
        /// <summary>
        /// Draw edges + Fill background with <see cref="IControlOverlay.BackColor"/>
        /// </summary>
        /// <seealso cref="IControlOverlay.BackColor"/>
        FullFill
    }

    /// <summary>
    /// Values to set if Opacity will affect <see cref="IControlOverlay.Childs"/> or not
    /// </summary>
    public enum OpacityRangeMode
    {
        /// <summary>
        /// Opacity will not be ported to <see cref="IControlOverlay.Childs"/>
        /// </summary>
        OnlyThis,
        /// <summary>
        /// Opacity will be applied to this + all <see cref="IControlOverlay.Childs"/>
        /// </summary>
        ThisAndChilds
    }

   
    /// <summary>
    /// This abstract class is the base class of all Overlay Controls.
    /// all its public fields and methods are into <see cref="IControlOverlay"/> interface.
    /// it is a wrapper of <see cref="System.Windows.Forms.Control"/> class
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class ControlOverlay<T> : GTAHookAdv.Overlay.IControlInterfaceEmbend where T : System.Windows.Forms.Control, new()
    {
       

        private T _ctrl;
        /// <summary>
        /// As we cannot inherite from ControlOverlay + System.Windows.Forms.Control, we use generics. Consider Ctrl as base, it is a T type.
        /// </summary>
        internal T Ctrl
        {
            get { return _ctrl; }
        }

#pragma warning disable 1591 //ignore no documentation comment warning for this
        [Browsable(false), Bindable(false), EditorBrowsable(EditorBrowsableState.Never)] //Hiden to intellisense
        public System.Windows.Forms.Control CtrlEmbended
        {
#pragma warning restore 1591
            get { return _ctrl as System.Windows.Forms.Control; }
            
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Parent"]/*' />
        public IControlOverlay Parent
        {
            get
            {
                if (_ctrl.Parent == null)
                    return null;
                else
                    return _ctrl.Parent.Tag as IControlOverlay; 
            }
            set
            {
                _ctrl.Parent = null; //To clean parent Childs, see Control.Controls on msdn
                if (value != null)
                {
                    IControlInterfaceEmbend newone = (IControlInterfaceEmbend)value;
                    _ctrl.Parent = newone.CtrlEmbended;
                }
            }
        }
        private Script _owner;

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Childs"]/*' />
        public IControlOverlay[] Childs
        {
            get
            {
                IControlOverlay[] result = new IControlOverlay[_ctrl.Controls.Count];
                for (int i = 0; i < _ctrl.Controls.Count; i++)
                {
                    result[i] = _ctrl.Controls[i].Tag as IControlOverlay;
                }
                return result;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="ChildAdd"]/*' />
        public void ChildAdd(IControlOverlay child)
        {
            if (child == null)
                throw new ArgumentNullException();
            IControlInterfaceEmbend newone = (IControlInterfaceEmbend)child;
            _ctrl.Controls.Add(newone.CtrlEmbended);
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="ChildRemove"]/*' />
        public void ChildRemove(IControlOverlay child)
        {
            if (child == null)
                throw new ArgumentNullException();
            IControlInterfaceEmbend newone = (IControlInterfaceEmbend)child;
            _ctrl.Controls.Remove(newone.CtrlEmbended);
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="ChildRemoveAll"]/*' />
        public void ChildRemoveAll()
        {
            _ctrl.Controls.Clear();
        }
        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="OwnerScript"]/*' />
        public Script OwnerScript
        {
            get { return _owner; }

        }

        /// <summary>
        /// Abstract constructor, it needs the calling script as it'll submit to PerFrameDrawing event to gets Graphics object.
        /// </summary>
        /// <param name="owner">you should simply fill with 'this' keyword from your script.</param>
        public ControlOverlay(Script owner)
        {
            if (owner == null)
                throw new ArgumentNullException("Script owner");
            _owner = owner;
            _owner.PerFrameDrawing += PerFrameDrawing;
            _ctrl = new T();
            
            _ctrl.Tag = this;
            MaximumSize = new Size(1920, 1080);
            this.BackColorChanged += ControlOverlay_BackColorChanged;
            this.BorderColorChanged += ControlOverlay_BorderColorChanged;
            ControlOverlay_BackColorChanged(this, EventArgs.Empty);
            this.ForeColorChanged += ControlOverlay_ForeColorChanged;
            ControlOverlay_ForeColorChanged(this, EventArgs.Empty);
            this.OpacityChanged += ControlOverlay_BackColorChanged;
            this.OpacityChanged += ControlOverlay_BorderColorChanged;
            this.OpacityChanged += ControlOverlay_ForeColorChanged;
            this.LocationChanged += UpdateBorderPos;
            this.SizeChanged += UpdateBorderPos;
            this.ParentChanged += ControlOverlay_ParentChanged;
            this.BackColor = Color.Transparent;
            this.ForeColor = Color.White;
            this.BorderColor = Color.Transparent;
            UpdateBorderPos(this, EventArgs.Empty);
        }

       

        void ControlOverlay_ParentChanged(object sender, EventArgs e)
        {
            //When parent change, if it is not null the parent will decide if PerFrameDrawing can be called or not.
            //e.g : if parent not visible it will decide to not call drawing on its childs.
            _owner.PerFrameDrawing -= PerFrameDrawing;
            if (Parent == null)
                _owner.PerFrameDrawing += PerFrameDrawing;
            else
                RaiseLocationChanged(this); //Everything depending on Location (so its parent location) will be recalculated
        }

        private PointF _TopLeft;
        private PointF _TopRight;
        private PointF _BottomRight;
        private PointF _BottomLeft;

       

        

        private Color _bordercolor;
        

        public Color BorderColor
        {
            get { return _bordercolor; }
            set {
                Color old = _bordercolor;
                _bordercolor = value;
                if (old != _bordercolor && BorderColorChanged != null)
                    BorderColorChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler BorderColorChanged;

        private void UpdateBorderPos(object sender, EventArgs e)
        {
            _TopLeft = PointToScreen(this.Location);
            _TopRight = PointToScreen(new PointF(this.Right, this.Top));
            _BottomRight = PointToScreen(new PointF(this.Right,this.Bottom));
            _BottomLeft = PointToScreen(new PointF(this.Left, this.Bottom));
            //Inform childs that their parent location changed.
            foreach (IControlOverlay curchild in Childs)
            {
                //This is the only way i found to trig LocationChanged Event (as this is the embended Form.Control that own it). If you have a better idea, thanks to tell me...
                RaiseLocationChanged(curchild);
            }
        }

        private static void RaiseLocationChanged(IControlOverlay curchild)
        {
            Point pos = curchild.Location;
            curchild.Location = new Point(1, 1); //Will trig LocationChanged event
            curchild.Location = pos; //Will trig it a second time, not cool but what to do else???
        }

        /// <summary>
        /// Draw borders that match <see cref="Location"/> and <see cref="Size"/>
        /// Moders don't have to call it as it will be automaticly called when needed.
        /// Many Controls have a BorderStyle Field.
        /// </summary>
        protected void DrawBorders()
        {
            if (BackColor != Color.Transparent)
            {
                DrawLine(_TopLeft, _TopRight, 2, BorderColorTransparent, DrawOptions.IgnoreOpacity);
                DrawLine(_TopRight, _BottomRight, 2, BorderColorTransparent, DrawOptions.IgnoreOpacity);
                DrawLine(_BottomRight, _BottomLeft, 2, BorderColorTransparent, DrawOptions.IgnoreOpacity);
                DrawLine(_BottomLeft, _TopLeft, 2, BorderColorTransparent, DrawOptions.IgnoreOpacity);
            }
        }

        void ControlOverlay_ForeColorChanged(object sender, EventArgs e)
        {
            _foreColorFinal = Color.FromArgb(OpacityInternal, this.ForeColor);
        }

        void ControlOverlay_BackColorChanged(object sender, EventArgs e)
        {
            _backColorFinal = Color.FromArgb(OpacityInternal, this.BackColor);
        }

        void ControlOverlay_BorderColorChanged(object sender, EventArgs e)
        {
            _bordercolorFinal = Color.FromArgb(OpacityInternal, this.BorderColor);
        }
        
        /// <summary>
        /// See <see cref="IDisposable.Dispose"/>
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
        public virtual void Dispose()
        {
            
            this.ParentChanged -= ControlOverlay_ParentChanged;
            this.OpacityChanged -= ControlOverlay_BackColorChanged;
            this.OpacityChanged -= ControlOverlay_BorderColorChanged;
            this.OpacityChanged -= ControlOverlay_ForeColorChanged;
            this.BackColorChanged -= ControlOverlay_BackColorChanged;
            this.BorderColorChanged -= ControlOverlay_BorderColorChanged;
            this.ForeColorChanged -= ControlOverlay_ForeColorChanged;
            this.LocationChanged -= UpdateBorderPos;
            this.SizeChanged -= UpdateBorderPos;
            if (_oldFontFinal != null)
                _oldFontFinal.Dispose();
            _oldFontFinal = null;
            _oldFont = null; //I don't dispose it, this is the childclass that must do it if it wants to...
            ChildRemoveAll();
            _ctrl.Dispose();
            _owner.PerFrameDrawing -= PerFrameDrawing;
            
        }

        /// <summary>
        /// This destructor ensure that <see cref="Dispose"/> will be called.
        /// But keep in mind that we can't guess when it will happens !
        /// </summary>
        ~ControlOverlay()
        {
            this.Dispose();
        }



        
        /// <summary>
        /// Every child class must implement this to say how the control must be drawn.
        /// <seealso cref="PerFrameDrawing"/>
        /// </summary>
        protected abstract void Draw();

        private GTA.Graphics _graphicslast;

        /// <summary>
        /// This is the graphic object from the owner script.
        /// <remarks>Controls usually don't need it. It his here if a control contains a <see cref="g_Texture"/> member.</remarks>
        /// </summary>
        protected GTA.Graphics Graphicslast
        {
            get { return _graphicslast; }
           
        }

        /// <summary>
        /// As you guess it is called on every frame from the owner script.
        ///<remarks> Depending of <see cref="Blink"/> , <see cref="Visible"/>,it will draw or not the control.
        ///If controls need to be drawn, then <see cref="Draw"/> will be called in the child class.</remarks> 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        [Browsable(false), Bindable(false), EditorBrowsable(EditorBrowsableState.Never)] //We hide as it should be private, see IControlInterfaceEmbend description
        public void PerFrameDrawing(object sender, GraphicsEventArgs e)
        {
            
            if (_blink && DateTime.Now.Millisecond > 500)
                return;
            if (!this.Visible || this.IsDisposed || this.Disposing)
                return;

            _graphicslast = e.Graphics;
            FontScaling lastScale = e.Graphics.Scaling;
            e.Graphics.Scaling = FontScaling.Pixel;

            //Draw Background
            if (BackColor != Color.Transparent)
                DrawRectangle(new System.Drawing.RectangleF(PointToScreen(this.Location), this.Size), BackColorTransparent, DrawOptions.IgnoreOpacity);

            //Draw control
            Draw();
            
            //Draw Childs
            foreach (IControlInterfaceEmbend curchild in Childs)
            {
                curchild.PerFrameDrawing(sender, e);
            }

            //Draw Borders
            if (BorderColor != Color.Transparent)
                DrawBorders();

            e.Graphics.Scaling = lastScale;
        }

        private ushort _opacity = 255;

        /// <summary>
        /// Opacity scalled from 0 to 255.
        /// <remarks>remember that <see cref="Opacity"/> is from 0 to 100 so modders can use it as percent</remarks>
        /// </summary>
        protected ushort OpacityInternal
        {
            get { return _opacity; }
        }

        

        private OpacityRangeMode _opacityRange = OpacityRangeMode.OnlyThis;

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="OpacityRange"]/*' />
        public OpacityRangeMode OpacityRange
        {
            get { return _opacityRange; }
            set
            {
                OpacityRangeMode old = _opacityRange;
                _opacityRange = value;
                OpacityPropagateToChilds();
                if (old != _opacityRange && OpacityRangeChanged != null)
                    OpacityRangeChanged(this, EventArgs.Empty);
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="OpacityRangeChanged"]/*' />
        public event EventHandler OpacityRangeChanged;

        bool CanChangeOpacity(IControlOverlay control)
        {
            if (control.Parent == null)
                return control.OpacityRange != OpacityRangeMode.ThisAndChilds;
            else
                return CanChangeOpacity(control.Parent);
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="OpacityChanged"]/*' />
        public event EventHandler OpacityChanged;

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Opacity"]/*' />
        public ushort Opacity
        {
            get { return Convert.ToUInt16(((float)_opacity) / 2.55f); }
            set
            {
                if (!CanChangeOpacity(this))
                    throw new InvalidOperationException("can't change Opacity because one parent has set OpacityRange to ThisAndChilds");
                if (value > 100) throw new ArgumentOutOfRangeException("opacity must be set from 0 to 100, received : " + value.ToString());
                _opacity = Convert.ToUInt16(((float)value) * 2.55f);
                OpacityPropagateToChilds();

                if (OpacityChanged != null)
                    OpacityChanged(this, EventArgs.Empty);

            }
        }

        private void OpacityPropagateToChilds()
        {
            if (OpacityRange == OpacityRangeMode.ThisAndChilds)
            {

                _opacityRange = OpacityRangeMode.OnlyThis; //Hack to avoid InvalidOperationException in Opacity setter
                try
                {
                    foreach (IControlOverlay curchild in Childs)
                    {
                        curchild.Opacity = this.Opacity;
                    }
                }
                finally
                {
                    _opacityRange = OpacityRangeMode.ThisAndChilds;
                }
            }
        }

        private bool _blink = false;

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Blink"]/*' />
        public bool Blink
        {
            get { return _blink; }
            set { _blink = value; }
        }

        

        #region NetScriptHook Draw Wrapper

        [Flags]
        internal enum DrawOptions
        {
            /// <summary>
            /// Ignore nothing (value by default)
            /// </summary>
            None = 0,
            /// <summary>
            /// Transparency will not be calculated
            /// </summary>
            IgnoreOpacity = 1,
            /// <summary>
            /// Coordinates will not be scaled to the screen resolution
            /// </summary>
            IgnoreScalingCoordinates = 2,
            /// <summary>
            /// Coordinates will not be scaled to the screen resolution
            /// </summary>
            IgnoreScalingFonts = 4
        }

        internal Color DrawPrepareColor(ref Color color, DrawOptions options)
        {
            Color finalColor = color;
            if ((options & ~DrawOptions.IgnoreOpacity) == options)
                finalColor = Color.FromArgb(_opacity, color);
            return finalColor;
        }

        internal void DrawLine(PointF p1, PointF p2, float width, Color color)
        {
            DrawLine(p1, p2, width, color, DrawOptions.None);
        }

       

        internal void DrawLine(PointF p1, PointF p2, float width, Color color,DrawOptions options)
        {
            Color finalColor = DrawPrepareColor(ref color, options);
            PointF p1Final = p1;
            PointF p2Final = p2;
            float widthFinal = width;
            if ((options & ~DrawOptions.IgnoreScalingCoordinates) == options)
            {
                p1Final = ResolutionHelper.ConvertToScr(p1);
                p2Final = ResolutionHelper.ConvertToScr(p2);
                widthFinal = ResolutionHelper.ConvertToScrX(Convert.ToInt32(width));
            }

            _graphicslast.DrawLine(p1Final, p2Final, widthFinal, finalColor);
        }

       

        
        /// <summary>
        /// Draw a filled rectangle. Color will not be transformed (if it is a half transparent colors, will be draw as a half transparent color).
        /// </summary>
        /// <param name="rect">this define location and size of the rectangle</param>
        /// <param name="color">an ARGB color</param>
        /// <seealso cref="DrawRectangle(RectangleF, Color, DrawOptions)"/>
        protected void DrawRectangle(RectangleF rect, Color color)
        {
            DrawRectangle(rect, color, DrawOptions.None);
        }

        /// <summary>
        /// Draw a filled rectangle.
        /// <remarks>Depending of <see cref="Opacity"/> value and <paramref name="options"/>, the <paramref name="color"/> will be transformed to inject transparency in it.
        /// set as internal for Testing purpose, but should be protected
        /// </remarks>
        /// </summary>
        /// <param name="rect">location and size of the rectangle to draw</param>
        /// <param name="color">a RGB color (transparency (Alpha) should be injected, see remarks)</param>
        /// <param name="options">see <see cref="DrawOptions"/></param>
        internal void DrawRectangle(RectangleF rect, Color color, DrawOptions options)
        {
            Color finalColor = DrawPrepareColor(ref color, options);
            RectangleF rectFinal = rect;
            if ((options & ~DrawOptions.IgnoreScalingCoordinates) == options)
            {
                rectFinal = ResolutionHelper.ConvertToScr(rect);
            }
            _graphicslast.DrawRectangle(rectFinal, finalColor);
        }


        /// <summary>
        /// Build or Rebuild the font, transparency and effects are automaticly managed
        /// </summary>
        /// <param name="textRegion">region where to display the text</param>
        /// <param name="font"> font to be build or rebuilt. It is a ref so the old font will automaticly disposed (important as it consumes graphic card memory)</param>
        internal void FontBuild(RectangleF textRegion, ref GTA.Font font)
        {
            FontBuild(textRegion, ref font, DrawOptions.None);
        }
        /// <summary>
        /// Build or Rebuild the font, transparency and effects are automaticly managed
        /// </summary>
        /// <param name="textRegion">region where to display the text</param>
        /// <param name="font"> font to be build or rebuilt. It is a ref so the old font will automaticly disposed (important as it consumes graphic card memory)</param>
        /// <param name="options">all options are available in this method</param>
        internal void FontBuild(RectangleF textRegion, ref GTA.Font font, DrawOptions options)
        {
            if (font != null)
                font.Dispose();
            int HeightFinal = this.Height;
            if((options & ~DrawOptions.IgnoreScalingCoordinates) == options)
                HeightFinal = ResolutionHelper.ConvertToScrY(this.Height);
            RectangleF textRegionFinal = textRegion;
            if ((options & ~DrawOptions.IgnoreScalingFonts) == options)
                textRegionFinal = ResolutionHelper.ConvertToScr(textRegion);

            Color colorFinal = BorderColor;
            Color EdgeColorFinalWhite = Color.White;
            Color EdgeColorFinalBlack = Color.Black;
            if ((options & ~DrawOptions.IgnoreOpacity) == options)
            {
                colorFinal = BorderColorTransparent;
                EdgeColorFinalBlack = Color.FromArgb(OpacityInternal, Color.Black);
                EdgeColorFinalWhite = Color.FromArgb(OpacityInternal, Color.White);
            }
            if (HeightFinal > 19)
                font = new GTA.Font(textRegionFinal.Height, FontScaling.Pixel, true, false); //Bold
            else
                font = new GTA.Font(textRegionFinal.Height, FontScaling.Pixel);
            font.Color = colorFinal;

            if (HeightFinal < 24)
                font.Effect = FontEffect.None;
            else
            {
                font.Effect = FontEffect.Edge;
                Color edgeColor;
                if (BackColor.GetBrightness() < 100)
                    edgeColor = EdgeColorFinalWhite;
                else
                    edgeColor = EdgeColorFinalBlack;
                font.EffectColor = edgeColor;
                font.EffectSize = 1;
            }
        }


        /// <summary>
        /// Draw a text.  For performance reasons, There is no Opacity and FontScale option, also no color aguments. Transparency and color have to be setted directly into the font.
        /// </summary>
        /// <param name="text">text to display</param>
        /// <param name="rect">aera to paint the text</param>
        /// <param name="alignment"></param>
        /// <param name="font">the font define the size,color,transparancy of the text, use FontBuild</param>
        protected void DrawText(String text, RectangleF rect, TextAlignment alignment, GTA.Font font)
        {
            DrawText(text, rect, alignment, font, DrawOptions.None);
        }

        GTA.Font _oldFont; //Used withDrawText to avoid cloning font on each frame
        GTA.Font _oldFontFinal;
        /// <summary>
        /// Draw a text.  For performance reasons, There is no Opacity and FontScale option, also no color aguments. Transparency and color have to be setted directly into the font.
        /// </summary>
        /// <param name="text">text to display</param>
        /// <param name="rect">aera to paint the text</param>
        /// <param name="alignment"></param>
        /// <param name="font">the font define the size,color,transparancy of the text, use FontBuild</param>
        /// <param name="options">only IgnoreScallingCoordinate will be considered, for others options do it with FontBuild</param>
        internal void DrawText(String text, RectangleF rect, TextAlignment alignment, GTA.Font font, DrawOptions options)
        {
            GTA.Font drawfont;
            RectangleF rectFinal = rect;
            if ((options & ~DrawOptions.IgnoreScalingCoordinates) == options)
            {
                rectFinal = ResolutionHelper.ConvertToScr(rect);
            }
            if(((options & ~DrawOptions.IgnoreOpacity) == options))
            {
                if (_oldFont != null && _oldFont == font)
                    drawfont = _oldFontFinal;
                else
                {
                    drawfont = TextHelper.CloneFont(font);
                    drawfont.Color = Color.FromArgb(OpacityInternal, font.Color);
                    drawfont.EffectColor = Color.FromArgb(OpacityInternal, font.EffectColor);
                    _oldFontFinal = drawfont;
                    _oldFont = font;
                }
            }
            else
            {
                drawfont = font;
            }
            _graphicslast.DrawText(text, rectFinal, alignment, drawfont);
        }

       
        #endregion
        //Can't use Control.BackColor because it refuse Transparent Color :(
        private Color _backColor;

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="BackColor"]/*' />
        public virtual Color BackColor
        {

            get
            {
                return _backColor;
            }
            set
            {
                _backColor = value;
            }
        }

        #region fields To Route

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="PointToScreen"]/*' />
        public PointF PointToScreen(PointF p)
        {
            Point p2 = new Point(Convert.ToInt32(p.X), Convert.ToInt32(p.Y));
            return PointToScreen(p2);
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="PointToScreen"]/*' />
        public Point PointToScreen(Point p)
        {
            if (this.Parent == null)
                return p;
            else
            {
                p.Offset(this.Parent.PointToScreen(this.Parent.Location));
                return p;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="ParentChanged"]/*' />
        public event EventHandler ParentChanged
        {
            add
            {
                _ctrl.ParentChanged += value;
            }
            remove
            {
                _ctrl.ParentChanged -= value;
            }
        }
       
        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="LocationChanged"]/*' />
        public event EventHandler LocationChanged
        {
            add
            {
                _ctrl.LocationChanged += value;
            }
            remove
            {
                _ctrl.LocationChanged -= value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="SizeChanged"]/*' />
        public event EventHandler SizeChanged
        {
            add
            {
                _ctrl.SizeChanged += value;
            }
            remove
            {
                _ctrl.SizeChanged -= value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="BackColorChanged"]/*' />
        public event EventHandler BackColorChanged
        {
            add
            {
                _ctrl.BackColorChanged += value;
            }
            remove
            {
                _ctrl.BackColorChanged -= value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="ForeColorChanged"]/*' />
        public event EventHandler ForeColorChanged
        {
            add
            {
                _ctrl.ForeColorChanged += value;
            }
            remove
            {
                _ctrl.ForeColorChanged -= value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Location"]/*' />
        public Point Location
        {
            get
            {
               return _ctrl.Location;
            }
            set
            {
                _ctrl.Location = value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Width"]/*' />
        public int Width
        {
            
            get
            {
                return _ctrl.Width;
            }
            set
            {
                _ctrl.Width = value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Height"]/*' />
        public int Height
        {

            get
            {
                return _ctrl.Height;
            }
            set
            {
                _ctrl.Height = value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Top"]/*' />
        public int Top
        {
            get { return _ctrl.Top; }
            set { _ctrl.Top = value; }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Bottom"]/*' />
        public int Bottom
        {
            get { return _ctrl.Bottom; }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Left"]/*' />
        public int Left
        {
            get { return _ctrl.Left; }
            set { _ctrl.Left = value; }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Right"]/*' />
        public int Right
        {
            get { return _ctrl.Right; }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="Size"]/*' />
        public virtual Size Size
        {

            get
            {
                return _ctrl.Size;
            }
            set
            {
                _ctrl.Size = value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="MinimumSize"]/*' />
        public Size MinimumSize
        {
            get
            {
                return Ctrl.MinimumSize;
            }
            set
            {
                Ctrl.MinimumSize = value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Field[@name="MaximumSize"]/*' />
        public Size MaximumSize
        {
            get
            {
                return Ctrl.MaximumSize;
            }
            set
            {
                Size old = Ctrl.MaximumSize;
                Ctrl.MaximumSize = value;
                if(!old.Equals(Ctrl.MaximumSize) && MaximumSizeChanged != null)
                    MaximumSizeChanged(this,EventArgs.Empty);
            }
        }

        public event EventHandler MaximumSizeChanged;

        

        Color _backColorFinal;

        

        /// <summary>
        /// Return BackColor, considering Opacity field
        /// </summary>
        public virtual Color BackColorTransparent
        {

            get
            {
                return _backColorFinal;
            }
            
        }

        private Color _bordercolorFinal;

        /// <summary>
        /// Return BackColor, considering Opacity field
        /// </summary>
        public virtual Color BorderColorTransparent
        {

            get
            {
                return _bordercolorFinal;
            }

        }


        Color _foreColorFinal;

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="ForeColor"]/*' />
        public virtual Color ForeColor
        {

            get
            {
                return _ctrl.ForeColor;
            }
            set
            {
                _ctrl.ForeColor = value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="ForeColorTransparent"]/*' />
        public virtual Color ForeColorTransparent
        {

            get
            {
                return _foreColorFinal;
            }

        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="Text"]/*' />
        public virtual string Text
        {
            get { return _ctrl.Text; }
            set { _ctrl.Text = value; }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Event[@name="TextChanged"]/*' />
        public event EventHandler TextChanged
        {
            add { Ctrl.TextChanged += value; }
            remove { Ctrl.TextChanged -= value; }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="IsDisposed"]/*' />
        public bool IsDisposed
        {
            
            get
            {
                return _ctrl == null || _ctrl.IsDisposed;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="Visible"]/*' />
        public bool Visible
        {
            
            get
            {
                return _ctrl.Visible;
            }
           
            set
            {
                _ctrl.Visible = value;
            }
        }

        /// <include file='ControlOverlay.doc' path='IControlOverlay/Method[@name="Disposing"]/*' />
        public bool Disposing
        {
            get { return _ctrl.Disposing; }
        }
        
        #endregion

    }
}
